/**
 * Copyright (C), 2015-2022, 成都启迪信息技术有限公司
 * FileName: SignerCommon
 * Author:   sjk
 * Date:     2022-08-08 16:33
 * Description:
 * <author>          <time>          <version>          <desc>
 * 作者姓名         修改时间           版本号            描述
 */
package com.qd.panda.dc;

import com.cdqidi.exception.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 〈一句话功能简述〉<br>
 *
 * @author sjk
 * @create 2022-08-08 16:33
 * @since 1.0.0
 */
@Slf4j
public class SignerCommon {
    public static final String PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCfGO4QTXI+GaVCEAYKh"
            + "+hyS8a+ujjbgpl4jEkf6DG0kYZx6xmBilcJ5mqqqLQ0qzXTT28R1euDtEYiIkmJ4PQgT3TTh+dB5IK+NIDuHOR/9gxRdooZndW+OHePVTeH4Wd0IplQoCoNW5/VI2Licq2r+uLNgDhJ9322wLS7CoCVZFn8WHBvOLM8UjMv9SnxC+ORFlVj6D6qKAq6+/lpWRyG3vl6YKPb5Dirf5kTeyqL6sl349OiXmcXvLn4QbRpL+/k+tYg9t542VPmW10D4AmlivC0evH34SI9TAN+rC2Cm+XeSpO2Ng/m5Xcw3uM3bCErlRMfWWmvr789013Qbn+vAgMBAAECggEARg7ZTi58XyI15mhd8Kc2UZZSt0wTm33gDPhhfv5lXOk0NdfcDHIZr89aKzpM2GCIPDvfYhA8PGvW8lL85Q09EzlJ7ZgL2rVAaXd/SttIN5zmgbzcRTl+lNwSsfhJkrlMMBTIRHuy6Nzu/hEuCx+KoI/C7dFHeDLWlfI346FVS/MJ3zcF5XgxDPrXjWiKy1cpyLpGdWi7EWBP5qLaLhVF5B6OfpqBEtgRUex9LQEFhNYKhPy20XGK9eThOiFjaSsCFeOInjXBOVsp9cren3tXhjsD0gGhDDCrC0qsL5viKeWVj7sZVC7boStVrzaz+iS0zTomsl0dPwqVCA/z4pRE2QKBgQDRG7+f9fYs0mME4T9QJynQMtBfYlBjmZvDkQIUxm6XGApQccjT5FeEVtXBo64nQ0aDTTroKNEOk2dGRB2f4Un22blGRe/dYnZbktUGLJhYYSXvVU5Qkb9JksVbF/5vS2D0YY5pjaroKMFNkFbNUKGPdWg/O0DdCjQnKoA2asPSxQKBgQDCxjUdib/vQ59kmBIBvkxfUf7lYF3B1dseUtrGuZOmiPN0N0VPBy23IAR2wmBnbTFlKSHLPwCQXPMA8XDlUyiAPlQEdFz+PSy/2Mg8cEYK3X1NQrRH7jYmO2Vsgyu6GgeztXLSMaAi2s/NqxofWabx43Xlfqt4O8fmOIUWbn3f4wKBgGP24fq0eMUgppmUnNHShxiy0g5nT4rtyhsJ3XbVDdVJdtTSMHGrfXMUmAeEGiNG9BSc/QYzTQ2sxfg/Y/Ikn1lU6E+B65NoGLDaVuAmvYWym5H4tAGsS0f+1D4iEE5gOK9bW9t2EDgAE7jiwbxRSYrtU7K2vuFsmVYH6VcaXxcJAoGAZ02GyFbR9I2yEUFSc5hBm2C6x19X+sF5CNk67aFpfS8vqFjUKrkM9w5FL9OiG9jfFN8+7DRLEUYrIDnt/cMgPPxRxVcOJ0282TeZ4+xMSeD1Xy/cvDXMhHSGM4pSe87ofNjkwDTP0QyqoFN6dFwxXiOc2Q5Y1VkniaQ6eg46Nq8CgYEAv7x/ClA7VRnQbO72zYE/XLSWfevqZqdFi+vVwehEboOetriYMa5Dvt9AEr1zU+TdfwhVU8GX/Vlx3y1qOcZg2EttjLuZmZuLhAnpaSsdFnDTq7FJLUcjYF3vxbnTrmsb4tuaFkiroBLbASDF69IAEuz0wmVGLcCFD6EoZYQsdMc=";
    public static final String PUBLIC_KEY =
            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnxjuEE1yPhmlQhAGCofockvGvro424KZeIxJH+gxtJGGcesZgYpXCeZqqqi0NKs1009vEdXrg7RGIiJJieD0IE9004fnQeSCvjSA7hzkf/YMUXaKGZ3Vvjh3j1U3h+FndCKZUKAqDVuf1SNi4nKtq/rizYA4Sfd9tsC0uwqAlWRZ/FhwbzizPFIzL/Up8QvjkRZVY+g+qigKuvv5aVkcht75emCj2+Q4q3+ZE3sqi+rJd+PTol5nF7y5+EG0aS/v5PrWIPbeeNlT5ltdA+AJpYrwtHrx9+EiPUwDfqwtgpvl3kqTtjYP5uV3MN7jN2whK5UTH1lpr6+/PdNd0G5/rwIDAQAB";

    public static final String SIGN_FIELD = "sign";
    public static final String SIGN_TYPE_FIELD = "sign_type";

    public static final String RSA = "RSA";
    public static final String SHA_256_WITH_RSA = "SHA256WithRSA";
    public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    public static void main(String[] args) {
        String s = "app_id=1531472922548432896&biz_content={\"cancel\":false,\"plateNumber\":\"川A55555\"}&nonce=1557255078918197249&timestamp=2022-08-10 14:38:37";
        log.info(sign(s, PRIVATE_KEY));
    }

    /**
     * 计算签名
     *
     * @param content       待签名的内容
     * @param privateKeyPem 私钥
     * @return 签名值的Base64串
     */
    public static String sign(String content, String privateKeyPem) {
        try {
            byte[] encodedKey = privateKeyPem.getBytes();
            encodedKey = Base64.decodeBase64(encodedKey);
            PrivateKey privateKey = KeyFactory.getInstance(RSA).generatePrivate(new PKCS8EncodedKeySpec(encodedKey));

            Signature signature = Signature.getInstance(SHA_256_WITH_RSA);
            signature.initSign(privateKey);
            signature.update(content.getBytes(DEFAULT_CHARSET));
            byte[] signed = signature.sign();
            return new String(Base64.encodeBase64(signed));
        } catch (Exception e) {
            String errorMessage = "签名遭遇异常，content=" + content + " privateKeySize=" + privateKeyPem.length() + " reason=" + e.getMessage();
            log.error(errorMessage, e);
            throw new ApiException(e);
        }
    }


    public static String getSignContent(Map<String, String> params) {
        if (params == null) {
            return null;
        }
        StringBuilder content = new StringBuilder();
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        int index = 0;
        for (String key : keys) {
            String value = params.get(key);
            if (areNotEmpty(key, value)) {
                content.append(index == 0 ? "" : "&").append(key).append("=").append(value);
                index++;
            }
        }
        return content.toString();
    }

    /**
     * 检查指定的字符串列表是否不为空。
     */
    public static boolean areNotEmpty(String... values) {
        boolean result = true;
        if (values == null || values.length == 0) {
            result = false;
        } else {
            for (String value : values) {
                result &= !isEmpty(value);
            }
        }
        return result;
    }

    /**
     * 检查指定的字符串是否为空。
     * <ul>
     * <li>SysUtils.isEmpty(null) = true</li>
     * <li>SysUtils.isEmpty("") = true</li>
     * <li>SysUtils.isEmpty("   ") = true</li>
     * <li>SysUtils.isEmpty("abc") = false</li>
     * </ul>
     *
     * @param value 待检查的字符串
     * @return true/false
     */
    public static boolean isEmpty(String value) {
        int strLen;
        if (value == null || (strLen = value.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((!Character.isWhitespace(value.charAt(i)))) {
                return false;
            }
        }
        return true;
    }
}